<?php

namespace App\Utils;

use App\Exceptions\ApiException;

class CommonUtil
{

    /**
     * 对提供的数据进行urlsafe的base64编码。
     *
     * @param string $data 待编码的数据，一般为字符串
     *
     * @return string 编码后的字符串
     * @link http://developer.qiniu.com/docs/v6/api/overview/appendix.html#urlsafe-base64
     */
    public static function base64_urlSafeEncode($data)
    {
        $find = array('+', '/');
        $replace = array('-', '_');
        return str_replace($find, $replace, base64_encode($data));
    }

    /**
     * 对提供的urlsafe的base64编码的数据进行解码
     *
     * @param string $str 待解码的数据，一般为字符串
     *
     * @return string 解码后的字符串
     */
    public static function base64_urlSafeDecode($str)
    {
        $find = array('-', '_');
        $replace = array('+', '/');
        return base64_decode(str_replace($find, $replace, $str));
    }

    public static function throwException($code, $msg)
    {
        throw new ApiException($code, $msg);
    }

    /**
     * 返回地区的全称 如 传入内蒙古 返回 内蒙古自治区
     *
     * @param string $province
     * @param string $city
     * @param string $region
     * @return array
     */
    public static function getFullAddress($province = '', $city = '', $region = '')
    {
        $result = [];
        if ($province) {
            $provinces = [
                '河北',
                '山西',
                '辽宁',
                '吉林',
                '黑龙江',
                '江苏',
                '浙江',
                '安徽',
                '福建',
                '江西',
                '山东',
                '河南',
                '湖北',
                '湖南',
                '广东',
                '海南',
                '四川',
                '贵州',
                '云南',
                '陕西',
                '甘肃',
                '青海'
            ];
            $municipalities = ['北京', '天津', '上海', '重庆'];
            $autonomousRegion = [
                '内蒙古' => '内蒙古自治区',
                '广西' => '广西壮族自治区',
                '西藏' => '西藏自治区',
                '新疆' => '新疆维吾尔自治区',
                '宁夏' => '宁夏回族自治区'
            ];

            if (in_array($province, $provinces)) {
                $province .= '省';
                //普通省里中的 特殊城市名
                $cities = [
                    '延边' => '延边朝鲜族自治州',
                    '大兴安岭' => '大兴安岭地区',
                    '济源' => '省直辖县级行政区划',
                    '恩施' => '恩施土家族苗族自治州',
                    '湘西' => '湘西土家族苗族自治州',
                    '阿坝' => '阿坝藏族羌族自治州',
                    '甘孜' => '甘孜藏族自治州',
                    '凉山' => '凉山彝族自治州',
                    '黔西' => '黔西南布依族苗族自治州',
                    '黔东' => '黔东南苗族侗族自治州',
                    '黔南' => '黔南布依族苗族自治州',
                    '楚雄' => '楚雄彝族自治州',
                    '红河' => '红河哈尼族彝族自治州',
                    '文山' => '文山壮族苗族自治州',
                    '西双版纳' => '西双版纳傣族自治州',
                    '大理' => '大理白族自治州',
                    '德宏' => '德宏傣族景颇族自治州',
                    '怒江' => '怒江傈傈族自治州',
                    '迪庆' => '迪庆藏族自治州',
                    '临夏' => '临夏回族自治州',
                    '甘南' => '甘南藏族自治州',
                    '海东' => '海东地区',
                    '海北' => '海北藏族自治州',
                    '黄南' => '黄南藏族自治州',
                    '海南' => '海南藏族自治州',
                    '果洛' => '果洛藏族自治州',
                    '玉树' => '玉树藏族自治州',
                    '海西' => '海西蒙古族藏族自治州'
                ];
                if (isset($cities[$city])) {
                    $city = $cities[$city];
                } else {
                    $city .= '市';
                }
            } elseif (in_array($province, $municipalities)) {
                $province .= '市';
                //直辖市中的特殊地名
                $cities = [
                    '密云' => '密云县',
                    '延庆' => '延庆县',
                    '宁河' => '宁河县',
                    '静海' => '静海县',
                    '蓟县' => '蓟县',
                    '崇明' => '崇明县',
                    '潼南' => '潼南县',
                    '铜梁' => '铜梁县',
                    '荣昌' => '荣昌县',
                    '璧山' => '璧山县',
                    '梁平' => '梁平县',
                    '城口' => '城口县',
                    '丰都' => '丰都县',
                    '垫江' => '垫江县',
                    '武隆' => '武隆县',
                    '忠县' => '忠县',
                    '开县' => '开县',
                    '云阳' => '云阳县',
                    '奉节' => '奉节县',
                    '巫山' => '巫山县',
                    '巫溪' => '巫溪县',
                    '石柱' => '石柱土家族自治县',
                    '秀山' => '秀山土家族苗族自治县',
                    '酉阳' => '酉阳土家族苗族自治县',
                    '彭水' => '彭水苗族土家族自治县'
                ];
                if (isset($cities[$city])) {
                    $region = $cities[$city];
                    $city = '县';
                } else {
                    $region = $city . '区';
                    $city = $province;
                }
            } elseif (array_key_exists($province, $autonomousRegion)) {
                $province = $autonomousRegion[$province];
                //自治区中的特殊地名
                $cities = [
                    '兴安' => '兴安盟',
                    '锡林' => '锡林郭勒盟',
                    '阿拉' => '阿拉善盟',
                    '昌都' => '昌都地区',
                    '山南' => '山南地区',
                    '日喀则' => '日喀则地区',
                    '那曲' => '那曲地区',
                    '阿里' => '阿里地区',
                    '林芝' => '林芝地区',
                    '吐鲁番' => '吐鲁番地区',
                    '哈密' => '哈密地区',
                    '昌吉' => '昌吉回族自治区',
                    '博尔塔拉' => '博尔塔拉蒙古自治州',
                    '巴音郭楞' => '巴音郭楞蒙古自治州',
                    '阿克苏' => '阿克苏地区',
                    '克孜勒苏' => '克孜勒苏柯尔克牧自治州',
                    '喀什' => '喀什地区',
                    '和田' => '和田地区',
                    '伊犁' => '伊犁哈萨克自治州',
                    '塔城' => '塔城地区',
                    '阿勒泰' => '阿勒泰地区'
                ];
                if (isset($cities[$city])) {
                    $city = $cities[$city];
                } else {
                    $city .= '市';
                }
            }
            $result = ['province' => $province, 'city' => $city, 'region' => $region];
        }
        return $result;
    }

    //二维数组排序
    public static function arraySort($arr, $keys, $type = 'desc', $limit = 0, $returnKey = null)
    {
        $keysvalue = $new_array = [];
        foreach ($arr as $k => $v) {
            $keysvalue[$k] = get_property($v, $keys);
        }
        if ($type == 'asc') {
            asort($keysvalue);
        } else {
            arsort($keysvalue);
        }
        reset($keysvalue);

        $i = 0;
        foreach ($keysvalue as $k => $v) {
            if ($returnKey == null) {
                $new_array[] = $arr[$k];
            } else {
                $new_array[] = get_property($arr[$k], $returnKey);
            }
            if ($limit > 0) {
                if (++$i >= $limit) {
                    break;
                }
            }
        }
        return $new_array;
    }

    /**
     * 二维数组排序
     * @param $arr
     * @param $keys
     * @param string $type
     * @param int $limit
     * @param null $returnKey
     * @param bool $defaultKey 原样返回key
     * @return array
     */
    public static function arrayDefaultSort($arr, $keys, $type = 'desc', $limit = 0, $returnKey = null, $defaultKey = false)
    {
        $keysvalue = $new_array = [];
        foreach ($arr as $k => $v) {
            $keysvalue[$k] = get_property($v, $keys);
        }
        if ($type == 'asc') {
            asort($keysvalue);
        } else {
            arsort($keysvalue);
        }
        reset($keysvalue);

        $i = 0;
        foreach ($keysvalue as $k => $v) {
            if ($returnKey == null) {
                $new_array[] = $arr[$k];
            } elseif ($defaultKey) {
                $new_array[$k] = $arr[$k];
            } else {
                $new_array[] = get_property($arr[$k], $returnKey);
            }
            if ($limit > 0) {
                if (++$i >= $limit) {
                    break;
                }
            }
        }
        return $new_array;
    }

    /**
     * 截取UTF-8编码下字符串的函数
     *
     * @param string $str 被截取的字符串
     * @param int $length 截取的长度
     * @param bool $append 是否附加省略号
     *
     * @return  string
     */
    public static function subStr($str, $length = 0, $append = true)
    {
        $str = str_replace("\n", '', str_replace("\r", '', trim($str)));
        $strlength = strlen($str);

        if ($length == 0 || $length >= $strlength) {
            return $str;
        } elseif ($length < 0) {
            $length = $strlength + $length;
            if ($length < 0) {
                $length = $strlength;
            }
        }

        if (function_exists('mb_substr')) {
            $newstr = mb_substr($str, 0, $length, 'utf-8');
        } elseif (function_exists('iconv_substr')) {
            $newstr = iconv_substr($str, 0, $length, 'utf-8');
        } else {
            $newstr = substr($str, 0, $length);
        }

        if ($append && $str != $newstr) {
            $newstr .= '...';
        }

        return $newstr;
    }


    /**
     * 从数组/对象中取属性
     *
     * @param $obj
     * @param $property
     * @param null $default
     * @return null
     */
    public static function getProperty($obj, $property, $default = null)
    {
        if (!$obj) {
            return $default;
        }
        is_string($obj) and $obj = json_decode($obj, true);
        if (is_object($obj)) {
            return property_exists($obj, $property) ? $obj->$property : $default;
        }

        return isset($obj[$property]) ? $obj[$property] : $default;
    }

    /**
     * 格式化座机号码
     *
     * @param $txt
     * @return mixed
     */
    public static function formatMobile($txt)
    {
        if (strlen($txt) != 11) {
            return $txt;
        } else {
            return preg_replace('/(\d{3})-?(\d{4})-?(\d{1,4}).*/', "$1-$2-$3", $txt);
        }
    }

    /**
     * 拼接认证图片URL
     * @param string $image 图片主体
     * @param int $size 大小
     * @param string $type
     * @return string
     */
    public static function combineCertifyImgUrl($image, $size = 0, $type = '')
    {
        if ($type == 'mark') { //打水印
            $url = config('app.CDNURL') . 'mcert/' . $image;
        } else {
            $url = config('app.CDNURL') . 'certify/' . $image;
        }

        if ($size > 0) {
            $url .= '/w/' . $size;
        }
        return $url;
    }

    /**
     * 转换城市列表的格式
     * @param $city
     * @return array
     */
    public static function toChangeCity($city)
    {
        $cityList = [];
        $i = 0;
        foreach ($city as $key => $v) {
            $cityList[$i] = [
                'provinceCode' => $key,
                'provinceName' => $v['provinceName'],
            ];
            foreach ($v['cityList'] as $_key => $val) {
                $cityList[$i]['cityList'][] = [
                    'cityCode' => $_key,
                    'cityName' => $val,
                ];
            }
            $i++;
        }
        return $cityList;
    }

    /**
     * 过滤代码
     * @param $str
     * @return string
     */
    public static function strFilter($str)
    {
        $str = str_replace('`', '', $str);
        $str = str_replace('·', '', $str);
        $str = str_replace('~', '', $str);
        $str = str_replace('!', '', $str);
        $str = str_replace('！', '', $str);
        $str = str_replace('@', '', $str);
        $str = str_replace('#', '', $str);
        $str = str_replace('$', '', $str);
        $str = str_replace('￥', '', $str);
        $str = str_replace('%', '', $str);
        $str = str_replace('^', '', $str);
        $str = str_replace('……', '', $str);
        $str = str_replace('&', '', $str);
        $str = str_replace('*', '', $str);
        $str = str_replace('(', '', $str);
        $str = str_replace(')', '', $str);
        $str = str_replace('（', '', $str);
        $str = str_replace('）', '', $str);
        $str = str_replace('-', '', $str);
        $str = str_replace('_', '', $str);
        $str = str_replace('——', '', $str);
        $str = str_replace('+', '', $str);
        $str = str_replace('=', '', $str);
        $str = str_replace('|', '', $str);
        $str = str_replace('\\', '', $str);
        $str = str_replace('[', '', $str);
        $str = str_replace(']', '', $str);
        $str = str_replace('【', '', $str);
        $str = str_replace('】', '', $str);
        $str = str_replace('{', '', $str);
        $str = str_replace('}', '', $str);
        $str = str_replace(';', '', $str);
        $str = str_replace('；', '', $str);
        $str = str_replace(':', '', $str);
        $str = str_replace('：', '', $str);
        $str = str_replace('\'', '', $str);
        $str = str_replace('"', '', $str);
        $str = str_replace('“', '', $str);
        $str = str_replace('”', '', $str);
        $str = str_replace(',', '', $str);
        $str = str_replace('，', '', $str);
        $str = str_replace('<', '', $str);
        $str = str_replace('>', '', $str);
        $str = str_replace('《', '', $str);
        $str = str_replace('》', '', $str);
        $str = str_replace('.', '', $str);
        $str = str_replace('。', '', $str);
        $str = str_replace('/', '', $str);
        $str = str_replace('、', '', $str);
        $str = str_replace('?', '', $str);
        $str = str_replace('？', '', $str);
        return trim($str);
    }

    /**
     * 获取头信息
     * @return string
     */
    public static function getUserAgent()
    {
        return isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
    }

    /**
     * Web结果集格式化输出
     */
    public static function ajaxResult()
    {
        $result = [
            'status' => [
                'code' => '0',
                'msg' => ''
            ]
        ];
        $args = func_get_args();
        foreach ($args as $arg) {
            if (is_int($arg)) {
                $result['status']['code'] = strval($arg);
            } elseif (is_string($arg)) {
                $result['status']['msg'] = strval($arg);
            } elseif (is_array($arg)) {
                $result = $result + $arg;
            }
        }

        return $result;
    }

    /**
     * 返回成功 （内部业务使用）
     * @param array $data 数据对象
     * @param int $code 返回状态
     * @return array [data,code]
     */
    public static function returnSuccess($data = null, $code = 1001)
    {
        $result = [
            'data' => $data,
            'code' => $code
        ];
        return $result;
    }

    /**
     * 返回失败 (内部业务使用)
     * @param string $msg 错误信息
     * @param int $code 错误编号
     * @return array [code,msg]
     */
    public static function returnFail($msg = '', $code = 1000)
    {
        $result = [
            'code' => $code,
            'msg' => $msg
        ];
        return $result;
    }


    /**
     * 获取URL中的参数
     * @param $url
     * @param null $key
     * @return mixed
     */
    public static function getQuery($url, $key = null)
    {
        parse_str(parse_url($url, PHP_URL_QUERY), $output);
        if (!empty($key)) {
            return $output[$key];
        }
        return $output;
    }

    /**
     * 根据时间标记获取时间戳
     * @param string $sign
     * @return array
     */
    public static function convertDateSignToUnix($sign = 'today')
    {
        switch ($sign) {
            case "today"://今天
                $startDate = mktime(0, 0, 0);
                $endDate = mktime(23, 59, 59);
                break;
            case "yesterday"://昨天
                $startDate = mktime(0, 0, 0, date('m'), date('d') - 1, date('Y'));
                $endDate = mktime(23, 59, 59, date('m'), date('d') - 1, date('Y'));
                break;
            case "last30"://最近30天
                $startDate = mktime(0, 0, 0, date('m'), date('d') - 30, date('Y'));
                $endDate = mktime(23, 59, 59, date('m'), date('d') - 1, date('Y'));
                break;
            case "lastWeek"://上周
                $startDate = mktime(0, 0, 0, date('m'), date('d') - date('w') + 1 - 7, date('Y'));
                $endDate = mktime(23, 59, 59, date('m'), date('d') - date('w') + 7 - 7, date('Y'));
                break;
            case "lastMonth"://上月
                $startDate = mktime(0, 0, 0, date('m') - 1, 1, date('Y'));
                $endDate = mktime(23, 59, 59, date('m'), 1, date('Y')) - 24 * 3600;
                break;
            case "month"://本月
                $startDate = mktime(0, 0, 0, date('m'), 1, date('Y'));
                $endDate = mktime(23, 59, 59, date('m'), date('t'), date('Y'));
                break;
            case "lastTwoWeek"://最近2周
                $startDate = mktime(0, 0, 0, date('m'), date('d') - 14, date('Y'));
                $endDate = mktime(23, 59, 59, date('m'), date('d') - 1, date('Y'));
                break;
            default://默认今天
                $startDate = mktime(0, 0, 0);
                $endDate = mktime(23, 59, 59);
                break;
        }
        return [$startDate, $endDate];
    }


    /**
     * url增加query参数
     * @param $url
     * @param $appendQuery
     * @return string
     */
    public static function addQueryToUrl($url, $appendQuery)
    {
        $parsedUrl = parse_url($url);
        if (empty($parsedUrl['path'])) {
            $url .= '/';
        }

        $oldQuery = [];
        if (!empty($parsedUrl['query'])) {
            parse_str($parsedUrl['query'], $oldQuery);
        }

        $appendQuery = array_merge($oldQuery, $appendQuery);
        if ($index = strpos($url, '?')) {
            $url = substr($url, 0, $index);
        }

        return $url . '?' . http_build_query($appendQuery);
    }

    /**
     * 数组转对象
     *
     * @param $arr
     * @return object
     */
    public static function arrayToObject($arr)
    {
        if (is_array($arr)) {
            // 经测试，此种方式性能最高
            return json_decode(json_encode($arr));
        } else {
            return $arr;
        }
    }

    /**
     * 获取日期区间
     * @param        $first string 开始时间(2019-07-01)
     * @param        $last string 结束时间(2019-07-10)
     * @param string $step
     * @param string $format
     * @return array
     */
    public static function dateRange($first, $last, $format = 'Y-m-d', $step = '+1 day')
    {
        $dates = [];
        $current = strtotime($first);
        $last = strtotime($last);

        while ($current <= $last) {
            $dates[] = date($format, $current);
            $current = strtotime($step, $current);
        }

        return $dates;
    }

    /**
     * 二维数组根据key 排序
     * 请勿将外部参数直接传入以防止命令注入！！！
     * @param $sortArray
     * @param $cols
     * @return array
     * @author 丁圆圆
     */
    public static function arrayMSort($sortArray, $cols)
    {
        $colArr = [];
        foreach ($cols as $col => $order) {
            $colArr[$col] = [];
            foreach ($sortArray as $k => $row) {
                $colArr[$col]['_' . $k] = strtolower($row[$col]);
            }
        }
        $eval = 'array_multisort(';
        foreach ($cols as $col => $order) {
            $eval .= '$colArr[\'' . $col . '\'],' . $order . ',';
        }
        $eval = substr($eval, 0, -1) . ');';

        eval($eval);
        $ret = [];
        foreach ($colArr as $col => $arr) {
            foreach ($arr as $k => $v) {
                $k = substr($k, 1);
                if (!isset($ret[$k])) {
                    $ret[$k] = $sortArray[$k];
                }
                $ret[$k][$col] = $sortArray[$k][$col];
            }
        }

        $output = [];

        foreach ($ret as $item) {
            $output[] = $item;
        }

        return $output;
    }

    /**
     * 随机数组
     * @param     $arr
     * @param int $num
     * @return array|mixed
     */
    public static function arrayRandom($arr, $num = 1)
    {
        if (empty($arr)) {
            return [];
        }

        shuffle($arr);

        $r = array();
        for ($i = 0; $i < $num; $i++) {
            if (isset($arr[$i])) {
                $r[] = $arr[$i];
            }
        }

        return $r;
    }

    /**
     * 获取 x 分钟下一场分钟,返回的是时间戳
     * 例子1： x = 20, 当前时间是：2019-11-12 20：15, 那么返回 2019-11-12  20：20
     * 例子2： x = 20, 当前时间是：2019-11-12 20：55, 那么返回 2019-11-12  21：00
     * @param $perMinute
     * @return false|int
     */
    public static function getNextMinute($perMinute)
    {
        $currentMinute = date('i');
        $div = (int)($currentMinute / $perMinute) + 1;
        $nextMinute = $div * $perMinute;
        $nextMinute = $nextMinute >= 60 ? 0 : $nextMinute;

        if ($nextMinute == 0) {
            return strtotime(date('Y-m-d H:0', strtotime('+1hours')));
        } else {
            return strtotime(date('Y-m-d H:' . $nextMinute));
        }
    }

    /**
     * 格式化时间格式
     * @param int|string $sourceTime 需要格式化的时间
     * @return string
     */
    public static function formatDateStyle($sourceTime)
    {
        if (!$sourceTime) {
            return '';
        }
        if (!is_numeric($sourceTime)) {
            $sourceTime = strtotime($sourceTime);
        }
        $currentTime = time();

        $diffTime = $currentTime - $sourceTime;
        if (date('Ymd', strtotime('-1 day', $currentTime)) == date('Ymd', $sourceTime)) {
            return '昨天';
        } elseif ($diffTime < 60) {
            return '刚刚';
        } elseif ($diffTime < 3600) {
            return intval($diffTime / 60) . '分钟前';
        } elseif ($diffTime < 3600 * 24) {
            return intval($diffTime / 3600) . '小时前';
        } elseif ($diffTime < 31536000) {
            return ceil($diffTime / 86400) . '天前';
        } elseif ($diffTime >= 31536000) {
            return intval($diffTime / 31536000) . '年前';
        } else {
            return '';
        }
    }

    /**
     * 获取时间段文本描述
     * @param int $time 要查询的时间戳
     * @return string
     */
    public static function getTimeRangeText($time)
    {
        $sourceHour24 = date('G', $time);
        $timeRangeText = '';
        if ($sourceHour24 <= 5) {
            $timeRangeText = '凌晨';
        } elseif ($sourceHour24 <= 11) {
            $timeRangeText = '早上';
        } elseif ($sourceHour24 <= 12) {
            $timeRangeText = '中午';
        } elseif ($sourceHour24 <= 17) {
            $timeRangeText = '下午';
        } elseif ($sourceHour24 <= 23) {
            $timeRangeText = '晚上';
        }
        return $timeRangeText;
    }



}
